use std::collections::HashMap;

use core::fmt::{Display, Formatter};
use serde::{Deserialize, Serialize};
use serde_json::{value::Value as SerdeJsonValue, Number};

use super::ValueType;

#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum Value {
    #[serde(rename = "none")]
    None,
    String(String),
    Char(char),
    Timestamp(i64),
    DateTime(i64),
    Date(u32),
    Boolean(bool),
    Number(i64),
    Float(f64),
    Bytes(Vec<u8>),
    Array(Vec<Value>),
    Object(HashMap<String, Value>),
}

impl Value {
    pub fn value_from_key<'a>(&'a self, key: &String) -> Option<&'a Value> {
        match self {
            Value::Object(map) => {
                if let Some(v) = map.get(key) {
                    Some(v)
                } else {
                    None
                }
            }
            _ => None,
        }
    }
}

impl Default for Value {
    fn default() -> Self {
        Value::String(String::new())
    }
}

/// 重写比较操作符
impl PartialEq for Value {
    fn eq(&self, other: &Self) -> bool {
        match self {
            Value::String(v) => {
                let value_result: Result<String, _> = other.try_into();
                if let Ok(other_v) = &value_result {
                    v == other_v
                } else {
                    false
                }
            }
            Value::Char(v) => true,
            Value::Boolean(v) => {
                let value_result: Result<bool, _> = other.as_bool();
                if let Ok(other_v) = &value_result {
                    v == other_v
                } else {
                    false
                }
            }
            Value::Number(v) => {
                let value_result: Result<i64, _> = other.as_i64();
                if let Ok(other_v) = &value_result {
                    *v == *other_v
                } else {
                    false
                }
            }
            Value::Float(v) => {
                let value_result: Result<f64, _> = other.as_f64();
                if let Ok(other_v) = &value_result {
                    *v == *other_v
                } else {
                    false
                }
            }
            Value::Array(v) => {
                //TODO 深度比较
                false
            }
            Value::Object(v) => {
                //TODO 深度比较
                false
            }
            Value::Timestamp(v) => true,
            Value::DateTime(v) => true,
            Value::Date(v) => *v > 0,
            Value::Bytes(v) => true,
            Value::None => {
                let value_result: Result<bool, _> = other.as_bool();
                if let Ok(other_v) = &value_result {
                    if !other_v {
                        true
                    } else {
                        false
                    }
                } else {
                    false
                }
            }
        }
    }
    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}

impl TryFrom<String> for Value {
    type Error = anyhow::Error;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        let v: serde_json::Value =
            serde_json::from_str(value.as_str()).map_err(|err| anyhow::anyhow!("{}", err))?;
        v.try_into()
    }
}

impl TryInto<String> for Value {
    type Error = anyhow::Error;

    fn try_into(self) -> Result<String, Self::Error> {
        self.as_string()
    }
}

impl TryFrom<bool> for Value {
    type Error = anyhow::Error;

    fn try_from(value: bool) -> Result<Self, Self::Error> {
        Ok(Value::Boolean(value))
    }
}

impl TryInto<bool> for Value {
    type Error = anyhow::Error;

    fn try_into(self) -> Result<bool, Self::Error> {
        self.as_bool()
    }
}

impl TryInto<String> for &Value {
    type Error = anyhow::Error;

    fn try_into(self) -> Result<String, Self::Error> {
        match self {
            Value::String(str) => Ok(str.clone()),
            Value::Number(str) => Ok(str.to_string()),
            Value::DateTime(str) => Ok(str.to_string()),
            Value::Timestamp(str) => Ok(str.to_string()),
            Value::Boolean(str) => Ok(str.to_string()),
            Value::Date(str) => Ok(str.to_string()),
            Value::Float(str) => Ok(str.to_string()),
            _ => Ok(serde_json::to_string(self)?),
        }
    }
}

impl TryInto<u32> for &Value {
    type Error = anyhow::Error;

    fn try_into(self) -> Result<u32, Self::Error> {
        match self {
            Value::Number(str) => Ok((*str)
                .try_into()
                .map_err(|err| anyhow::anyhow!("value转u32错误{:?}", self))?),
            _ => Err(anyhow::anyhow!("value转u32错误!{:?}", self)),
        }
    }
}

impl TryInto<u32> for Value {
    type Error = anyhow::Error;

    fn try_into(self) -> Result<u32, Self::Error> {
        match self {
            Value::Number(str) => Ok(str
                .try_into()
                .map_err(|err| anyhow::anyhow!("value转u32错误"))?),

            _ => Err(anyhow::anyhow!("value转u32错误!")),
        }
    }
}

impl TryFrom<SerdeJsonValue> for Value {
    type Error = anyhow::Error;

    fn try_from(value: SerdeJsonValue) -> Result<Self, Self::Error> {
        //
        let v = match value {
            SerdeJsonValue::Array(array) => {
                let mut tv: Vec<Value> = vec![];
                for v in array {
                    tv.push(Value::try_from(v).map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?);
                }
                Value::Array(tv)
            }
            SerdeJsonValue::Bool(v) => Value::Boolean(v),
            SerdeJsonValue::Null => Value::None,
            SerdeJsonValue::Number(n) => {
                // TODO
                if n.is_f64() {
                    Value::Float(n.as_f64().map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?)
                } else if n.is_u64() {
                    Value::Number(n.as_i64().map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?)
                } else if n.is_i64() {
                    Value::Number(n.as_i64().map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?)
                } else {
                    Value::Number(n.as_i64().map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?)
                }
            }
            SerdeJsonValue::String(str) => Value::String(str),
            SerdeJsonValue::Object(obj) => {
                let mut map = HashMap::new();
                for (key, v) in obj {
                    map.insert(
                        key,
                        Value::try_from(v).map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?,
                    );
                }
                Value::Object(map)
            }
        };
        Ok(v)
    }
}

impl TryFrom<&SerdeJsonValue> for Value {
    type Error = anyhow::Error;

    fn try_from(value: &SerdeJsonValue) -> Result<Self, Self::Error> {
        //
        let v = match value {
            SerdeJsonValue::Array(array) => {
                let mut tv: Vec<Value> = vec![];
                for v in array {
                    tv.push(Value::try_from(v).map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?);
                }
                Value::Array(tv)
            }
            SerdeJsonValue::Bool(v) => Value::Boolean(v.clone()),
            SerdeJsonValue::Null => Value::None,
            SerdeJsonValue::Number(n) => {
                // TODO
                if n.is_f64() {
                    Value::Float(n.as_f64().map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?)
                } else if n.is_u64() {
                    Value::Number(n.as_i64().map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?)
                } else if n.is_i64() {
                    Value::Number(n.as_i64().map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?)
                } else {
                    Value::Number(n.as_i64().map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?)
                }
            }
            SerdeJsonValue::String(str) => Value::String(str.clone()),
            SerdeJsonValue::Object(obj) => {
                let mut map = HashMap::new();
                for (key, v) in obj {
                    map.insert(
                        key.clone(),
                        Value::try_from(v).map_or(Err(anyhow::anyhow!("")), |o| Ok(o))?,
                    );
                }
                Value::Object(map)
            }
        };
        Ok(v)
    }
}

impl TryInto<SerdeJsonValue> for Value {
    type Error = anyhow::Error;

    fn try_into(self) -> Result<SerdeJsonValue, Self::Error> {
        match self {
            Value::String(str) => Ok(SerdeJsonValue::String(str)),
            Value::Char(str) => Ok(SerdeJsonValue::String(str.to_string())),
            Value::Boolean(v) => Ok(SerdeJsonValue::Bool(v)),
            Value::Number(v) => Ok(SerdeJsonValue::Number(Number::from(v))),
            Value::Float(v) => Ok(SerdeJsonValue::Number(
                Number::from_f64(v as f64)
                    .map_or(Err(anyhow::anyhow!("Float类型转换失败!")), |o| Ok(o))?,
            )),
            // Value::Bytes(v) => Ok(SerdeJsonValue::Double(v)),
            Value::Array(array) => {
                let mut tv: Vec<SerdeJsonValue> = vec![];
                for v in array {
                    tv.push(
                        v.try_into()
                            .map_or(Err(anyhow::anyhow!("Array类型转换失败!")), |o| Ok(o))?,
                    );
                }
                Ok(SerdeJsonValue::Array(tv))
            }
            Value::Object(obj) => {
                let mut map = serde_json::Map::<String, SerdeJsonValue>::new();
                for (key, v) in obj {
                    map.insert(
                        key,
                        v.try_into()
                            .map_or(Err(anyhow::anyhow!("Object类型转换失败!")), |o| Ok(o))?,
                    );
                }
                Ok(SerdeJsonValue::Object(map))
            }
            Value::Timestamp(v) => Ok(SerdeJsonValue::Number(Number::from(v))),
            Value::DateTime(v) => Ok(SerdeJsonValue::Number(Number::from(v))),
            Value::Date(v) => Ok(SerdeJsonValue::Number(Number::from(v))),
            Value::Bytes(v) => Ok(SerdeJsonValue::Array(
                v.iter()
                    .map(|v| SerdeJsonValue::String(v.to_string()))
                    .collect(),
            )),
            Value::None => Ok(SerdeJsonValue::Null),
            // _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
}

impl TryInto<SerdeJsonValue> for &Value {
    type Error = anyhow::Error;

    fn try_into(self) -> Result<SerdeJsonValue, Self::Error> {
        match self {
            Value::String(str) => Ok(SerdeJsonValue::String(str.clone())),
            Value::Char(str) => Ok(SerdeJsonValue::String(str.to_string())),
            Value::Boolean(v) => Ok(SerdeJsonValue::Bool(*v)),
            Value::Number(v) => Ok(SerdeJsonValue::Number(Number::from(*v))),
            Value::Float(v) => Ok(SerdeJsonValue::Number(
                Number::from_f64(*v as f64)
                    .map_or(Err(anyhow::anyhow!("Float类型转换失败!")), |o| Ok(o))?,
            )),
            // Value::Bytes(v) => Ok(SerdeJsonValue::Double(v)),
            Value::Array(array) => {
                let mut tv: Vec<SerdeJsonValue> = vec![];
                for v in array {
                    tv.push(
                        v.try_into()
                            .map_or(Err(anyhow::anyhow!("Array类型转换失败!")), |o| Ok(o))?,
                    );
                }
                Ok(SerdeJsonValue::Array(tv))
            }
            Value::Object(obj) => {
                let mut map = serde_json::Map::<String, SerdeJsonValue>::new();
                for (key, v) in obj {
                    map.insert(
                        key.clone(),
                        v.try_into()
                            .map_or(Err(anyhow::anyhow!("Object类型转换失败!")), |o| Ok(o))?,
                    );
                }
                Ok(SerdeJsonValue::Object(map))
            }
            Value::Timestamp(v) => Ok(SerdeJsonValue::Number(Number::from(*v))),
            Value::DateTime(v) => Ok(SerdeJsonValue::Number(Number::from(*v))),
            Value::Date(v) => Ok(SerdeJsonValue::Number(Number::from(*v))),
            Value::Bytes(v) => Ok(SerdeJsonValue::Array(
                v.iter()
                    .map(|v| SerdeJsonValue::String(v.to_string()))
                    .collect(),
            )),
            Value::None => Ok(SerdeJsonValue::Null),
            // Value::Any(v) => Ok(Value::try_into(v)?),
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
}

/// ValueType ToString
impl Display for ValueType {
    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
        match self {
            ValueType::None => write!(f, "none"),
            ValueType::String => write!(f, "string"),
            ValueType::Char => write!(f, "char"),
            ValueType::Timestamp => write!(f, "timestamp"),
            ValueType::DateTime => write!(f, "datatime"),
            ValueType::Date => write!(f, "date"),
            ValueType::Boolean => write!(f, "boolean"),
            ValueType::Number => write!(f, "number"),
            ValueType::Float => write!(f, "float"),
            ValueType::Bytes => write!(f, "bytes"),
            ValueType::Array => write!(f, "array"),
            ValueType::Object => write!(f, "object"),
        }
    }
}

impl From<ValueType> for String {
    fn from(value_type: ValueType) -> Self {
        match value_type {
            ValueType::None => "none".into(),
            ValueType::String => "string".into(),
            ValueType::Char => "char".into(),
            ValueType::DateTime => "datatime".into(),
            ValueType::Date => "date".into(),
            ValueType::Timestamp => "timestamp".into(),
            ValueType::Boolean => "boolean".into(),
            ValueType::Number => "number".into(),
            ValueType::Float => "float".into(),
            ValueType::Bytes => "bytes".into(),
            ValueType::Array => "array".into(),
            ValueType::Object => "object".into(),
        }
    }
}

impl From<String> for ValueType {
    fn from(v_type: String) -> Self {
        match v_type {
            v_type if v_type == "string" => ValueType::String,
            v_type if v_type == "char" => ValueType::Char,
            v_type if v_type == "datatime" => ValueType::DateTime,
            v_type if v_type == "timestamp" => ValueType::Timestamp,
            v_type if v_type == "boolean" => ValueType::Boolean,
            v_type if v_type == "number" => ValueType::Number,
            v_type if v_type == "float" => ValueType::Float,
            v_type if v_type == "bytes" => ValueType::Bytes,
            v_type if v_type == "array" => ValueType::Array,
            v_type if v_type == "object" => ValueType::Object,
            _ => ValueType::None,
        }
    }
}

impl Value {
    pub fn as_bool(&self) -> anyhow::Result<bool> {
        Ok(match self {
            Value::String(v) => {
                if v == "" {
                    false
                } else {
                    true
                }
            }
            Value::Char(v) => true,
            Value::Boolean(v) => v.clone(),
            Value::Number(v) => {
                if *v > 0 {
                    true
                } else {
                    false
                }
            }
            Value::Float(v) => {
                if *v > 0.0 {
                    true
                } else {
                    false
                }
            }
            Value::Array(v) => v.len() > 0,
            Value::Object(v) => true,
            Value::Timestamp(v) => true,
            Value::DateTime(v) => true,
            Value::Date(v) => true,
            Value::Bytes(v) => v.len() > 0,
            Value::None => false,
        })
    }
    pub fn as_string(&self) -> anyhow::Result<String> {
        Ok(match self {
            Value::String(v) => v.clone(),
            Value::Char(v) => v.to_string(),
            Value::Boolean(v) => v.to_string(),
            Value::Number(v) => v.to_string(),
            Value::Float(v) => v.to_string(),
            Value::Array(v) => {
                serde_json::to_string(v).map_err(|err| anyhow::anyhow!("{}", err))?
            }
            Value::Object(v) => {
                serde_json::to_string(v).map_err(|err| anyhow::anyhow!("{}", err))?
            }
            Value::Timestamp(v) => v.to_string(),
            Value::DateTime(v) => v.to_string(),
            Value::Date(v) => v.to_string(),
            Value::Bytes(v) => {
                serde_json::to_string(v).map_err(|err| anyhow::anyhow!("{}", err))?
            }
            Value::None => String::from("none"),
        })
    }
    pub fn as_f64(&self) -> anyhow::Result<f64> {
        Ok(match self {
            Value::Boolean(v) => {
                if *v {
                    1.0
                } else {
                    0.0
                }
            }
            Value::Number(v) => (*v) as f64,
            Value::Float(v) => *v,
            Value::None => 0.0_f64,
            _ => 0.0_f64,
        })
    }
    pub fn as_i64(&self) -> anyhow::Result<i64> {
        Ok(match self {
            Value::Boolean(v) => {
                if *v {
                    1
                } else {
                    0
                }
            }
            Value::Number(v) => *v,
            Value::Float(v) => (*v).round() as i64,
            Value::None => 0_i64,
            _ => 0_i64,
        })
    }
    pub fn is_empty(&self) -> bool {
        match self {
            Value::Boolean(v) => !*v,
            Value::Number(v) => *v == 0,
            Value::Float(v) => *v == 0.0,
            Value::None => true,
            Value::String(v) => v == &String::new(),
            _ => false,
        }
    }
    pub fn is_array(&self) -> bool {
        match self {
            Value::Array(_) => true,
            _ => false,
        }
    }
    pub fn starts_with(&self, start: &String) -> bool {
        if let Ok(v) = self.as_string() {
            v.starts_with(start)
        } else {
            false
        }
    }
    pub fn ends_with(&self, start: &String) -> bool {
        if let Ok(v) = self.as_string() {
            v.ends_with(start)
        } else {
            false
        }
    }
    pub fn contains(&self, start: &String) -> bool {
        if let Ok(v) = self.as_string() {
            v.contains(start)
        } else {
            false
        }
    }
}
impl Value {
    pub fn from_string_by_type(str: &String, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::String => {
                return Ok(Value::String(str.clone()));
            }
            ValueType::Number => {
                // string to i64
                return Ok(Value::Number(
                    str.parse::<i64>()
                        .map_err(|err| anyhow::anyhow!("{}", err))?,
                ));
            }
            ValueType::Timestamp => {
                //
                Ok(Value::Timestamp(0))
            }
            ValueType::Boolean => {
                //true，false
                if str.to_lowercase().eq("true") {
                    return Ok(Value::Boolean(true));
                } else if str.to_lowercase().eq("false") {
                    return Ok(Value::Boolean(false));
                }
                return Err(anyhow::anyhow!("_类型转换失败!"));
            }
            ValueType::Array => Ok(Value::Array(vec![Value::String(str.clone())])),
            ValueType::None => Ok(Value::None),
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
    pub fn from_char_by_type(str: &char, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::Char => Ok(Value::Char(str.clone())),
            ValueType::String => {
                return Ok(Value::String(str.to_string()));
            }
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
    pub fn from_boolean_by_type(v: &bool, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::Boolean => Ok(Value::Boolean(v.clone())),
            ValueType::String => {
                return Ok(Value::String(v.to_string()));
            }
            ValueType::Number => {
                return Ok(Value::Number(if *v { 1_i64 } else { 0_i64 }));
            }
            ValueType::Float => {
                return Ok(Value::Float(if *v { 1_f64 } else { 0_f64 }));
            }
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
    pub fn from_number_by_type(v: &i64, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::Number => Ok(Value::Number(*v)),
            ValueType::Timestamp => Ok(Value::Timestamp(*v)),
            ValueType::DateTime => Ok(Value::DateTime(*v)),
            ValueType::Date => Ok(Value::Date(*v as u32)),
            ValueType::Boolean => Ok(Value::Boolean(*v > 0)),
            ValueType::String => {
                return Ok(Value::String(v.to_string()));
            }
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
    pub fn from_float_by_type(v: &f64, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::Float => Ok(Value::Float(*v)),
            ValueType::String => {
                return Ok(Value::String(v.to_string()));
            }
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
    pub fn from_array_by_type(v: &Vec<Value>, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::Array => Ok(Value::Array(v.clone())),
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
    pub fn from_object_by_type(
        v: &HashMap<String, Value>,
        value_type: &ValueType,
    ) -> anyhow::Result<Value> {
        match value_type {
            ValueType::Object => Ok(Value::Object(v.clone())),
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
    pub fn from_timestamp_by_type(v: &i64, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::Timestamp => Ok(Value::Timestamp(*v)),
            ValueType::Number => Ok(Value::Number(*v)),
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }

    pub fn from_datetime_by_type(v: &i64, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::DateTime => Ok(Value::DateTime(*v)),
            ValueType::Number => Ok(Value::Number(*v)),
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }

    pub fn from_date_by_type(v: &u32, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::DateTime => Ok(Value::DateTime(*v as i64)),
            ValueType::Date => Ok(Value::Date(*v as u32)),
            ValueType::Number => Ok(Value::Number(*v as i64)),
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }

    pub fn from_bytes_by_type(v: &Vec<u8>, value_type: &ValueType) -> anyhow::Result<Value> {
        match value_type {
            ValueType::Bytes => Ok(Value::Bytes(v.clone())),
            _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
}

impl Value {
    pub fn convert(&self, value_type: &ValueType) -> anyhow::Result<Value> {
        //
        match self {
            Value::String(v) => {
                //
                return Value::from_string_by_type(v, value_type);
            }
            Value::Char(v) => {
                //
                return Value::from_char_by_type(v, value_type);
            }
            Value::Boolean(v) => {
                //
                return Value::from_boolean_by_type(v, value_type);
            }
            Value::Number(v) => {
                //
                return Value::from_number_by_type(v, value_type);
            }
            Value::Float(v) => {
                return Value::from_float_by_type(v, value_type);
            }
            Value::Array(v) => {
                return Value::from_array_by_type(v, value_type);
            }
            Value::Object(v) => {
                return Value::from_object_by_type(v, value_type);
            }
            Value::Timestamp(v) => {
                return Value::from_timestamp_by_type(v, value_type);
            }
            Value::DateTime(v) => {
                return Value::from_datetime_by_type(v, value_type);
            }
            Value::Date(v) => {
                return Value::from_date_by_type(v, value_type);
            }
            Value::Bytes(v) => {
                return Value::from_bytes_by_type(v, value_type);
            }
            Value::None => Err(anyhow::anyhow!("_类型转换失败!")),
            // _ => Err(anyhow::anyhow!("_类型转换失败!")),
        }
    }
}
